home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / dflat2.zip / EDITBOX.C < prev    next >
Text File  |  1991-04-19  |  25KB  |  986 lines

  1. /* ------------- editbox.c ------------ */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include "dflat.h"
  8.  
  9. #define EDITBUFFERLENGTH  4096
  10. #define ENTRYBUFFERLENGTH 1024
  11. #define GROWLENGTH        1024
  12.  
  13.  
  14. #define EditBufLen(wnd) (isMultiLine(wnd) ? EDITBUFFERLENGTH : ENTRYBUFFERLENGTH)
  15. #define WndCol (wnd->CurrCol-wnd->wleft)
  16. #define CurrChar (wnd->CurrLine+wnd->CurrCol)
  17.  
  18. static void PasteText(WINDOW, char *, int);
  19. static void SaveDeletedText(WINDOW, char *, int);
  20. static void SetAnchor(WINDOW, int, int);
  21. static void Forward(WINDOW);
  22. static void Backward(WINDOW);
  23. static void End(WINDOW);
  24. static void Home(WINDOW);
  25. static void Downward(WINDOW);
  26. static void Upward(WINDOW);
  27. static char *FindLinePointer(WINDOW, int);
  28. static void StickEnd(WINDOW);
  29. static void UpLine(WINDOW);
  30. static void DownLine(WINDOW);
  31. static void NextWord(WINDOW);
  32. static void PrevWord(WINDOW);
  33. static void ResetEditBox(WINDOW);
  34. #define SetLinePointer(wnd, ln)    (wnd->CurrLine = FindLinePointer(wnd, ln))
  35.  
  36.  
  37. static int KeyBoardMarking;
  38. int TextMarking;
  39. static int dragcount = -1;
  40.  
  41. char *Clipboard;
  42. int ClipboardLength;
  43.  
  44.  
  45. int EditBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  46. {
  47.     int rtn;
  48.     static int py = -1;
  49.     int kx = (int) p1 - GetLeft(wnd);
  50.     int ky = (int) p2 - GetTop(wnd);
  51.     int c;
  52.     RECT rc = ClientRect(wnd);
  53.     char *lp;
  54.     int len;
  55.  
  56.     int    mx;
  57.     int    my;
  58.  
  59.     switch (msg)    {
  60.         case CREATE_WINDOW:
  61.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  62.             wnd->text = malloc(EditBufLen(wnd));
  63.             wnd->textlen = EditBufLen(wnd);
  64.             ResetEditBox(wnd);
  65.             return rtn;
  66.         case ADDTEXT:
  67.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  68.             if (!isMultiLine(wnd))    {
  69.                 wnd->CurrLine = wnd->text;
  70.                 wnd->CurrCol = strlen((char *)p1);
  71.                 if (wnd->CurrCol >= ClientWidth(wnd))    {
  72.                     wnd->wleft = wnd->CurrCol - ClientWidth(wnd);
  73.                     wnd->CurrCol -= wnd->wleft;
  74.                 }
  75.                 wnd->BlkEndCol = wnd->CurrCol;
  76.                 PostMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  77.             }
  78.             return rtn;
  79.         case SETTEXT:
  80.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  81.             wnd->CurrLine = wnd->text;
  82.             return rtn;
  83.         case CLEARTEXT:
  84.             ResetEditBox(wnd);
  85.             break;
  86.         case EB_GETTEXT:    {
  87.             char *cp1 = (char *)p1;
  88.             char *cp2 = wnd->text;
  89.             while (p2-- && *cp2 && *cp2 != '\n')
  90.                 *cp1++ = *cp2++;
  91.             *cp1 = '\0';
  92.             return TRUE;
  93.         }
  94.         case EB_PUTTEXT:
  95.             SendMessage(wnd, CLEARTEXT, 0, 0);
  96.             SendMessage(wnd, ADDTEXT, p1, p2);
  97.             return TRUE;
  98.         case SETFOCUS:
  99.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  100.             if (p1)    {
  101.                 SendMessage(NULLWND, SHOW_CURSOR, GetCommandToggle(ID_INSERT), 0);
  102.                 SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  103.             }
  104.             else
  105.                 SendMessage(NULLWND, HIDE_CURSOR, 0, 0);
  106.             return rtn;
  107.         case SHIFT_CHANGED:
  108.             if (!(p1 & (LEFTSHIFT | RIGHTSHIFT)) && KeyBoardMarking)    {
  109.                 SendMessage(wnd, BUTTON_RELEASED, 0, 0);
  110.                 KeyBoardMarking = FALSE;
  111.             }
  112.             break;
  113.         case DOUBLE_CLICK:
  114.             if (KeyBoardMarking)
  115.                 return TRUE;
  116.             break;
  117.         case LEFT_BUTTON:
  118.             if (KeyBoardMarking || TextMarking)
  119.                 return TRUE;
  120.             if (WindowMoving || WindowSizing)
  121.                 break;
  122.             if (!InsideRect(p1, p2, rc))
  123.                 break;
  124.  
  125.             mx = (int) p1 - GetClientLeft(wnd);
  126.             my = (int) p2 - GetClientTop(wnd);
  127.  
  128.             if (isMultiLine(wnd))    {
  129.  
  130.                 if (BlockMarked(wnd))    {
  131.                     ClearBlock(wnd);
  132.                     SendMessage(wnd, PAINT, 0, 0);
  133.                 }
  134.  
  135.                 if (wnd->wlines)    {
  136.                     if (my > wnd->wlines-1)
  137.                         break;
  138.                     lp = TextLine(wnd, my);
  139.                     len = (int) (strchr(lp, '\n') - lp);
  140.                     mx = min(mx, len);
  141.                     if (mx < wnd->wleft)    {
  142.                         mx = 0;
  143.                         SendMessage(wnd, KEYBOARD, HOME, 0);
  144.                     }
  145.                 }
  146.                 else
  147.                     mx = my = 0;
  148.  
  149.                 if (dragcount == -1)
  150.                     dragcount = 2;
  151.                 if (--dragcount == 0)    {
  152.                     SetAnchor(wnd, mx+wnd->wleft, my+wnd->wtop);
  153.                     TextMarking = TRUE;
  154.                     SendMessage(wnd, CAPTURE_MOUSE, TRUE, 0);
  155.                     return TRUE;
  156.                 }
  157.                 wnd->WndRow = my;
  158.                 SetLinePointer(wnd, my+wnd->wtop);
  159.             }
  160.             if (isMultiLine(wnd) || !BlockMarked(wnd))
  161.                 wnd->CurrCol = mx+wnd->wleft;
  162.             PostMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  163.             return TRUE;
  164.         case MOUSE_MOVED:
  165.             mx = (int) p1 - GetClientLeft(wnd);
  166.             my = (int) p2 - GetClientTop(wnd);
  167.             if (my > wnd->wlines-1)
  168.                 break;
  169.             if (TextMarking && !(WindowMoving || WindowSizing))    {
  170.                 int ptop;
  171.                 int pbot;
  172.                 char *lp;
  173.                 int len;
  174.                 int y;
  175.                 int bbl, bel;
  176.                 RECT rc = ClientRect(wnd);
  177.  
  178.                 if (!InsideRect(p1, p2, rc))    {
  179.                     if (p1 < GetClientLeft(wnd))
  180.                         p1 = GetClientLeft(wnd);
  181.                     if (p1 > GetClientRight(wnd))
  182.                         p1 = GetClientRight(wnd);
  183.                     if (p2 < GetClientTop(wnd))
  184.                         p2 = GetClientTop(wnd);
  185.                     if (p2 > GetClientBottom(wnd))
  186.                         p2 = GetClientBottom(wnd);
  187.                     SendMessage(NULLWND, MOUSE_CURSOR, p1, p2);
  188.                 }
  189.  
  190.                 ptop = min(wnd->BlkBegLine, wnd->BlkEndLine);
  191.                 pbot = max(wnd->BlkBegLine, wnd->BlkEndLine);
  192.  
  193.                 lp = TextLine(wnd, wnd->wtop+my);
  194.                 len = (int) (strchr(lp, '\n') - lp);
  195.                 mx = min(mx, len-wnd->wleft);
  196.  
  197.                 wnd->BlkEndCol = mx+wnd->wleft;
  198.                 wnd->BlkEndLine = my+wnd->wtop;
  199.  
  200.                 bbl = min(wnd->BlkBegLine, wnd->BlkEndLine);
  201.                 bel = max(wnd->BlkBegLine, wnd->BlkEndLine);
  202.  
  203.                 while (ptop < bbl)    {
  204.                     WriteTextLine(wnd, NULL, ptop-wnd->wtop, FALSE);
  205.                     ptop++;
  206.                 }
  207.                 for (y = bbl; y <= bel; y++)
  208.                     WriteTextLine(wnd, NULL, y-wnd->wtop, FALSE);
  209.                 while (pbot > bel)    {
  210.                     WriteTextLine(wnd, NULL, pbot-wnd->wtop, FALSE);
  211.                     --pbot;
  212.                 }
  213.                 return FALSE;
  214.             }
  215.             break;
  216.         case BUTTON_RELEASED:
  217.             if (!isMultiLine(wnd))
  218.                 break;
  219.             dragcount = -1;
  220.             if (TextMarking && !(WindowMoving || WindowSizing))    {
  221.                 PostMessage(wnd, RELEASE_MOUSE, 0, 0);
  222.                 TextMarking = FALSE;
  223.                 if (wnd->BlkBegLine > wnd->BlkEndLine)    {
  224.                     swap(wnd->BlkBegLine, wnd->BlkEndLine);
  225.                     swap(wnd->BlkBegCol, wnd->BlkEndCol);
  226.                 }
  227.                 if (wnd->BlkBegLine == wnd->BlkEndLine &&
  228.                         wnd->BlkBegCol > wnd->BlkEndCol)
  229.                     swap(wnd->BlkBegCol, wnd->BlkEndCol);
  230.                 return TRUE;
  231.             }
  232.             else
  233.                 py = -1;
  234.             break;
  235.         case SCROLL:
  236.             if (!isMultiLine(wnd))
  237.                 break;
  238.             if ((rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2)) != FALSE)    {
  239.                 if (p1)    {
  240.                     /* -------- scrolling up --------- */
  241.                     if (wnd->WndRow == 0)    {
  242.                         DownLine(wnd);
  243.                         StickEnd(wnd);
  244.                     }
  245.                     else
  246.                         --wnd->WndRow;
  247.                 }
  248.                 else    {
  249.                     /* -------- scrolling down --------- */
  250.                     if (wnd->WndRow == ClientHeight(wnd)-1)    {
  251.                         UpLine(wnd);
  252.                         StickEnd(wnd);
  253.                     }
  254.                     else
  255.                         wnd->WndRow++;
  256.                 }
  257.                 SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  258.             }
  259.             return rtn;
  260.         case HORIZSCROLL:
  261.             if (p1 && wnd->CurrCol == wnd->wleft &&
  262.                     *CurrChar == '\n')
  263.                 return FALSE;
  264.             if ((rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2)) != FALSE)    {
  265.                 if (wnd->CurrCol < wnd->wleft)
  266.                     wnd->CurrCol++;
  267.                 else if (WndCol == ClientWidth(wnd))
  268.                     --wnd->CurrCol;
  269.                 SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  270.             }
  271.             return rtn;
  272.         case MOVE:
  273.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  274.             SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  275.             return rtn;
  276.         case SIZE:
  277.             rtn = BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  278.             if (WndCol > ClientWidth(wnd)-1)
  279.                 wnd->CurrCol = ClientWidth(wnd)-1 + wnd->wleft;
  280.             if (wnd->WndRow > ClientHeight(wnd)-1)    {
  281.                 wnd->WndRow = ClientHeight(wnd)-1;
  282.                 SetLinePointer(wnd, wnd->WndRow+wnd->wtop);
  283.             }
  284.             SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  285.             return rtn;
  286.         case KEYBOARD:
  287.             if (WindowMoving || WindowSizing)
  288.                 break;
  289.             c = (int) p1;
  290.             if ((p2 & ALTKEY) || 
  291.                     c == SHIFT_INS || c == SHIFT_DEL)
  292.                 break;
  293.             if ((p2 & CTRLKEY) && c != CTRL_FWD  &&
  294.                                   c != CTRL_BS   &&
  295.                                   c != CTRL_HOME &&
  296.                                   c != CTRL_END)
  297.                 break;
  298.             if (c == ESC)
  299.                 break;
  300.             if (isMultiLine(wnd))    {
  301.                 if (p2 & (LEFTSHIFT | RIGHTSHIFT))    {
  302.                     SendMessage(NULLWND, CURRENT_KEYBOARD_CURSOR,
  303.                         (PARAM) &kx, (PARAM)&ky);
  304.  
  305.                     kx -= GetClientLeft(wnd);
  306.                     ky -= GetClientTop(wnd);
  307.  
  308.                     switch (c)    {
  309.                         case HOME:
  310.                         case END:
  311.                         case PGUP:
  312.                         case PGDN:
  313.                         case UP:
  314.                         case DN:
  315.                         case FWD:
  316.                         case BS:
  317.                         case CTRL_FWD:
  318.                         case CTRL_BS:
  319.                             if (!KeyBoardMarking)    {
  320.                                 if (BlockMarked(wnd))    {
  321.                                     ClearBlock(wnd);
  322.                                     SendMessage(wnd, PAINT, 0, 0);
  323.                                 }
  324.                                 KeyBoardMarking = TextMarking = TRUE;
  325.                                 SetAnchor(wnd, kx+wnd->wleft, ky+wnd->wtop);
  326.                             }
  327.                             break;
  328.                         default:
  329.                             break;
  330.                     }
  331.                 }
  332.                 else if (((c != DEL && c != RUBOUT) ||
  333.                         !isMultiLine(wnd)) && BlockMarked(wnd))    {
  334.                     ClearBlock(wnd);
  335.                     SendMessage(wnd, PAINT, 0, 0);
  336.                 }
  337.             }
  338.             switch (c)    {
  339.                 case PGUP:
  340.                 case PGDN:
  341.                     if (!isMultiLine(wnd))
  342.                         break;
  343.                     BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  344.                     SetLinePointer(wnd, wnd->wtop+wnd->WndRow);
  345.                     StickEnd(wnd);
  346.                     SendMessage(wnd, KEYBOARD_CURSOR,WndCol, wnd->WndRow);
  347.                     break;
  348.                 case HOME:
  349.                     Home(wnd);
  350.                     break;
  351.                 case END:
  352.                     End(wnd);
  353.                     break;
  354.                 case CTRL_FWD:
  355.                     NextWord(wnd);
  356.                     break;
  357.                 case CTRL_BS:
  358.                     PrevWord(wnd);
  359.                     break;
  360.                 case CTRL_HOME:
  361.                     if (!isMultiLine(wnd))    {
  362.                         Home(wnd);
  363.                         break;
  364.                     }
  365.                     rtn = BaseWndProc(EDITBOX, wnd, msg, HOME, p2);
  366.                     Home(wnd);
  367.                     wnd->CurrLine = wnd->text;
  368.                     wnd->WndRow = 0;
  369.                     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  370.                     return rtn;
  371.                 case CTRL_END:
  372.                     if (!isMultiLine(wnd))    {
  373.                         End(wnd);
  374.                         break;
  375.                     }
  376.                     Home(wnd);
  377.                     rtn = BaseWndProc(EDITBOX, wnd, msg, END, p2);
  378.                     SetLinePointer(wnd, wnd->wlines-1);
  379.                     wnd->WndRow = min(ClientHeight(wnd)-1, wnd->wlines-1);
  380.                     End(wnd);
  381.                     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  382.                     return rtn;
  383.                 case UP:
  384.                     if (!isMultiLine(wnd))
  385.                         break;
  386.                     Upward(wnd);
  387.                     break;
  388.                 case DN:
  389.                     if (!isMultiLine(wnd))
  390.                         break;
  391.                     Downward(wnd);
  392.                     break;
  393.                 case FWD:
  394.                     Forward(wnd);
  395.                     break;
  396.                 case BS:
  397.                     Backward(wnd);
  398.                     break;
  399.             }
  400.             if (KeyBoardMarking)    {
  401.                 SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  402.                 SendMessage(NULLWND, CURRENT_KEYBOARD_CURSOR,
  403.                     (PARAM) &kx, (PARAM)&ky);
  404.                 SendMessage(wnd, MOUSE_MOVED, kx, ky);
  405.                 return TRUE;
  406.             }
  407.             if (!TestAttribute(wnd, READONLY))    {
  408.                 switch (c)    {
  409.                     case HOME:
  410.                     case END:
  411.                     case PGUP:
  412.                     case PGDN:
  413.                     case UP:
  414.                     case DN:
  415.                     case FWD:
  416.                     case BS:
  417.                     case CTRL_FWD:
  418.                     case CTRL_BS:
  419.                     case CTRL_HOME:
  420.                     case CTRL_END:
  421.                     case RUBOUT:
  422.                         if (!isMultiLine(wnd) && BlockMarked(wnd))    {
  423.                             ClearBlock(wnd);
  424.                             SendMessage(wnd, PAINT, 0, 0);
  425.                         }
  426.                         if (c != RUBOUT)
  427.                             break;
  428.                         if (wnd->CurrLine == wnd->text && wnd->CurrCol == 0)
  429.                             break;
  430.                         Backward(wnd);
  431.                         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  432.                     case DEL:
  433.                         if (BlockMarked(wnd))    {
  434.                             SendMessage(wnd, COMMAND, ID_DELETETEXT, 0);
  435.                             return TRUE;
  436.                         }
  437.                         if (*(CurrChar+1) == '\0')
  438.                             return TRUE;
  439.                         if (isMultiLine(wnd) &&
  440.                                 *CurrChar == '\n')
  441.                             --wnd->wlines;
  442.                         if (*(CurrChar+1))    {
  443.                             int repaint = *CurrChar == '\n';
  444.                             strcpy(CurrChar, CurrChar+1);
  445.                             if (repaint)
  446.                                 SendMessage(wnd, PAINT, 0, 0);
  447.                             else
  448.                                 WriteTextLine(wnd, NULL, wnd->WndRow, FALSE);
  449.                         }
  450.                         wnd->TextChanged = TRUE;
  451.                         break;
  452.                     case INS:
  453.                         InvertCommandToggle(ID_INSERT);
  454.                         SendMessage(NULLWND, SHOW_CURSOR, GetCommandToggle(ID_INSERT), 0);
  455.                         break;
  456.                     case '\r':
  457.                         if (isMultiLine(wnd))
  458.                             c = '\n';
  459.                     default:
  460.                         if (c == '\t')    {
  461.                             int insmd = GetCommandToggle(ID_INSERT);
  462.                             if (!isMultiLine(wnd))
  463.                                 PostMessage(GetParent(wnd), msg, p1, p2);
  464.                             else do    {
  465.                                 if (!insmd && *(CurrChar+1) == '\0')
  466.                                     break;
  467.                                 SendMessage(wnd, KEYBOARD,
  468.                                     insmd ? ' ' : FWD, 0);
  469.                             } while (wnd->CurrCol % cfg.Tabs);
  470.                             return TRUE;
  471.                         }
  472.                         if ((c != '\n' && c < ' ') || (c & 0x1000))
  473.                             /* ---- not recognized by editor --- */
  474.                             break;
  475.                         if (!isMultiLine(wnd) && BlockMarked(wnd))    {
  476.                             ResetEditBox(wnd);
  477.                             ClearBlock(wnd);
  478.                         }
  479.                         if (*CurrChar == '\0')    {
  480.                             *CurrChar = '\n';
  481.                             *(CurrChar+1) = '\0';
  482.                             wnd->wlines++;
  483.                         }
  484.                         /* --- displayable char or newline --- */
  485.                         if (c == '\n' ||
  486.                                 GetCommandToggle(ID_INSERT) ||
  487.                                     *CurrChar == '\n')    {
  488.                             char *cp = wnd->CurrLine;
  489.                             while (*cp && *cp != '\n')
  490.                                 cp++;
  491.                             wnd->textwidth = max(wnd->textwidth,
  492.                                         (int) (cp-wnd->CurrLine+1));
  493.                             /* ------ insert mode ------ */
  494.                             memmove(CurrChar+1, CurrChar, strlen(CurrChar)+1);
  495.                             WriteTextLine(wnd, NULL, wnd->WndRow, FALSE);
  496.                             if (strlen(wnd->text) == wnd->textlen)    {
  497.                                 int dif = (int) (wnd->CurrLine - wnd->text);
  498.                                 wnd->textlen += GROWLENGTH;
  499.                                 wnd->text = realloc(wnd->text, wnd->textlen);
  500.                                 wnd->CurrLine = wnd->text + dif;
  501.                             }
  502.                         }
  503.                         /* ----- put the char in the buffer ----- */
  504.                         *CurrChar = c;
  505.                         wnd->TextChanged = TRUE;
  506.                         if (c == '\n')    {
  507.                             wnd->wleft = 0;
  508.                             wnd->wlines++;
  509.                             End(wnd);
  510.                             Forward(wnd);
  511.                             SendMessage(wnd, PAINT, 0, 0);
  512.                             break;
  513.                         }
  514.                         /* ---------- test end of window --------- */
  515.                         if (WndCol == ClientWidth(wnd)-1)    {
  516.                             int dif;
  517.                             char *cp = CurrChar;
  518.                             while (*cp != ' ' && cp != wnd->CurrLine)
  519.                                 --cp;
  520.                             if (!isMultiLine(wnd) || cp == wnd->CurrLine ||
  521.                                     !GetCommandToggle(ID_WRAP))
  522.                                 SendMessage(wnd, HORIZSCROLL, TRUE, 0);
  523.                             else    {
  524.                                 dif = 0;
  525.                                 if (c != ' ')    {
  526.                                     dif = (int) (CurrChar - cp);
  527.                                     wnd->CurrCol -= dif;
  528.                                     SendMessage(wnd, KEYBOARD, DEL, 0);
  529.                                     --dif;
  530.                                 }
  531.                                 SendMessage(wnd, KEYBOARD, '\r', 0);
  532.                                 wnd->CurrCol = dif;
  533.                                 if (c == ' ')
  534.                                     break;
  535.                             }
  536.                         }
  537.                         /* ------ display the character ------ */
  538.                         SetStandardColor(wnd);
  539.                         PutWindowChar(wnd, WndCol, wnd->WndRow, c);
  540.                         /* ----- advance the pointers ------ */
  541.                         wnd->CurrCol++;
  542.                         break;
  543.                 }
  544.             }
  545.             SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  546.             return TRUE;
  547.         case COMMAND:    {
  548.             char *bbl, *bel, *bb;
  549.             int len;
  550.  
  551.             if (BlockMarked(wnd))    {
  552.                 bbl = FindLinePointer(wnd, wnd->BlkBegLine) + wnd->BlkBegCol;
  553.                 bel = FindLinePointer(wnd, wnd->BlkEndLine) + wnd->BlkEndCol;
  554.                 len = (int) (bel - bbl);
  555.             }
  556.             switch ((int)p1)    {
  557.                 case ID_CUT:
  558.                 case ID_COPY:
  559.                     ClipboardLength = len;
  560.                     Clipboard = realloc(Clipboard, ClipboardLength);
  561.                     if (Clipboard != NULL)
  562.                         memmove(Clipboard, bbl, ClipboardLength);
  563.                 case ID_DELETETEXT:
  564.                     if (p1 != ID_COPY)    {
  565.                         if (p1 != ID_CUT)
  566.                             SaveDeletedText(wnd, bbl, len);
  567.                         wnd->TextChanged = TRUE;
  568.                         strcpy(bbl, bel);
  569.                         wnd->CurrLine = bbl - wnd->BlkBegCol;
  570.                         wnd->CurrCol = wnd->BlkBegCol;
  571.                         wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  572.                         if (wnd->WndRow < 0)    {
  573.                             wnd->wtop = wnd->BlkBegLine;
  574.                             wnd->WndRow = 0;
  575.                         }
  576.                         wnd->wlines -= wnd->BlkEndLine - wnd-> BlkBegLine;
  577.                         SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  578.                     }
  579.                     ClearBlock(wnd);
  580.                     SendMessage(wnd, PAINT, 0, 0);
  581.                     return TRUE;
  582.                 case ID_CLEAR:
  583.                     SaveDeletedText(wnd, bbl, len);
  584.                     wnd->CurrLine = bbl;
  585.                     wnd->CurrCol = wnd->BlkBegCol;
  586.                     wnd->WndRow = wnd->BlkBegLine - wnd->wtop;
  587.                     if (wnd->WndRow < 0)    {
  588.                         wnd->WndRow = 0;
  589.                         wnd->wtop = wnd->BlkBegLine;
  590.                     }
  591.                     while (bbl < bel)    {
  592.                         char *cp = strchr(bbl, '\n');
  593.                         if (cp > bel)
  594.                             cp = bel;
  595.                         strcpy(bbl, cp);
  596.                         bel -= (int) (cp - bbl);
  597.                         bbl++;
  598.                     }
  599.                     ClearBlock(wnd);
  600.                     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  601.                     SendMessage(wnd, PAINT, 0, 0);
  602.                     wnd->TextChanged = TRUE;
  603.                     return TRUE;
  604.                 case ID_PASTE:
  605.                     if (Clipboard != NULL)    {
  606.                         PasteText(wnd, Clipboard, ClipboardLength);
  607.                         wnd->TextChanged = TRUE;
  608.                     }
  609.                     return TRUE;
  610.                 case ID_UNDO:
  611.                     if (wnd->DeletedText != NULL)    {
  612.                         PasteText(wnd, wnd->DeletedText, wnd->DeletedLength);
  613.                         free(wnd->DeletedText);
  614.                         wnd->DeletedText = NULL;
  615.                     }
  616.                     return TRUE;
  617.                 case ID_PARAGRAPH:    {
  618.                     char *bl;
  619.                     int bc, ec;
  620.                     int fl, el;
  621.                     int Blocked;
  622.  
  623.                     el = wnd->BlkEndLine;
  624.                     ec = wnd->BlkEndCol;
  625.                     if (!BlockMarked(wnd))    {
  626.                         Blocked = FALSE;
  627.                         /* ---- forming paragraph from cursor position --- */
  628.                         fl = wnd->wtop + wnd->WndRow;
  629.                         bl = wnd->CurrLine;
  630.                         bc = wnd->CurrCol;
  631.                         Home(wnd);
  632.                         bbl = bel = bl;
  633.                         if (bc >= ClientWidth(wnd))
  634.                             bc = 0;
  635.                         /* ---- locate the end of the paragraph ---- */
  636.                         while (*bel)    {
  637.                             int blank = TRUE;
  638.                             char *bll = bel;
  639.                             /* --- blank line marks end of paragraph --- */
  640.                             while (*bel && *bel != '\n')    {
  641.                                 if (*bel != ' ')
  642.                                     blank = FALSE;
  643.                                 bel++;
  644.                             }
  645.                             if (blank)    {
  646.                                 bel = bll;
  647.                                 break;
  648.                             }
  649.                             if (*bel)
  650.                                 bel++;
  651.                         }
  652.                         if (bel == bbl)    {
  653.                             SendMessage(wnd, KEYBOARD, DN, 0);
  654.                             return TRUE;
  655.                         }
  656.                         if (*bel == '\0')
  657.                             --bel;
  658.                         if (*bel == '\n')
  659.                             --bel;
  660.                     }
  661.                     else    {
  662.                         Blocked = TRUE;
  663.                         /* ---- forming paragraph from marked block --- */
  664.                         fl = wnd->BlkBegLine;
  665.                         bc = wnd->CurrCol = wnd->BlkBegCol;
  666.                         wnd->CurrLine = FindLinePointer(wnd, fl);
  667.                         if (fl < wnd->wtop)
  668.                             wnd->wtop = fl;
  669.                         wnd->WndRow = fl - wnd->wtop;
  670.                         SendMessage(wnd, KEYBOARD, '\r', 0);
  671.                         el++, fl++;
  672.                         if (bc != 0)    {
  673.                             SendMessage(wnd, KEYBOARD, '\r', 0);
  674.                             el++, fl ++;
  675.                         }
  676.                         bc = 0;
  677.                         bl = wnd->CurrLine = FindLinePointer(wnd, fl);
  678.                         bbl = bl + bc;
  679.                         bel = FindLinePointer(wnd, el) + ec;
  680.                     }
  681.  
  682.                     /* --- change all newlines in block to spaces --- */
  683.                     while (CurrChar < bel)    {
  684.                         if (*CurrChar == '\n')    {
  685.                             *CurrChar = ' ';
  686.                             wnd->CurrLine = CurrChar + 1;
  687.                             wnd->CurrCol = 0;
  688.                             --wnd->wlines;
  689.                         }
  690.                         else
  691.                             wnd->CurrCol++;
  692.                     }
  693.  
  694.                     /* ---- insert newlines at new margin boundaries ---- */
  695.                     bb = bbl;
  696.                     while (bbl < bel)    {
  697.                         bbl++;
  698.                         if ((int)(bbl - bb) == ClientWidth(wnd)-1)    {
  699.                             while (*bbl != ' ' && bbl > bb)
  700.                                 --bbl;
  701.                             if (*bbl != ' ')    {
  702.                                 bbl = strchr(bbl, ' ');
  703.                                 if (bbl == NULL || bbl >= bel)
  704.                                     break;
  705.                             }
  706.                             *bbl = '\n';
  707.                             wnd->textwidth = max(wnd->textwidth,
  708.                                 (int) (bbl-bb));
  709.                             wnd->wlines++;
  710.                             bb = bbl+1;
  711.                         }
  712.                     }
  713.                     ec = (int)(bel - bb);
  714.  
  715.                     if (Blocked)    {
  716.                         /* ---- position cursor at end of new paragraph ---- */
  717.                         if (el < wnd->wtop ||
  718.                                 wnd->wtop + ClientHeight(wnd) < el)
  719.                             wnd->wtop = el-ClientHeight(wnd);
  720.                         if (wnd->wtop < 0)
  721.                             wnd->wtop = 0;
  722.                         wnd->WndRow = el - wnd->wtop;
  723.                         wnd->CurrLine = FindLinePointer(wnd, el);
  724.                         wnd->CurrCol = ec;
  725.                         SendMessage(wnd, KEYBOARD, '\r', 0);
  726.                         SendMessage(wnd, KEYBOARD, '\r', 0);
  727.                     }
  728.                     else    {
  729.                         /* --- put cursor back at beginning --- */
  730.                         wnd->CurrLine = bl;
  731.                         wnd->CurrCol = bc;
  732.                         if (fl < wnd->wtop)
  733.                             wnd->wtop = fl;
  734.                         wnd->WndRow = fl - wnd->wtop;
  735.                     }
  736.                     SendMessage(wnd, PAINT, 0, 0);
  737.                     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  738.                     wnd->TextChanged = TRUE;
  739.                     return TRUE;
  740.                 }
  741.                 default:
  742.                     break;
  743.             }
  744.             break;
  745.         }
  746.         case CLOSE_WINDOW:
  747.             SendMessage(NULLWND, HIDE_CURSOR, 0, 0);
  748.             if (wnd->DeletedText != NULL)
  749.                 free(wnd->DeletedText);
  750.             break;
  751.         default:
  752.             break;
  753.     }
  754.     return BaseWndProc(EDITBOX, wnd, msg, p1, p2);
  755. }
  756.  
  757. static void PasteText(WINDOW wnd, char *SaveTo, int len)
  758. {
  759.     int plen = strlen(wnd->text) + len + 1;
  760.     char *bl = CurrChar;
  761.     char *el = bl+len;
  762.     if (plen > wnd->textlen)    {
  763.         wnd->text = realloc(wnd->text, plen);
  764.         wnd->textlen = plen;
  765.     }
  766.     memmove(el,    bl,    strlen(bl)+1);
  767.     memmove(bl, SaveTo, len);
  768.     while (bl < el)
  769.         if (*bl++ == '\n')
  770.             wnd->wlines++;
  771.     SendMessage(wnd, PAINT, 0, 0);
  772. }
  773.  
  774. static void SaveDeletedText(WINDOW wnd, char *bbl, int len)
  775. {
  776.     wnd->DeletedLength = len;
  777.     if ((wnd->DeletedText = realloc(wnd->DeletedText, len)) != NULL)
  778.         memmove(wnd->DeletedText, bbl, len);
  779. }
  780.  
  781. static void SetAnchor(WINDOW wnd, int mx, int my)
  782. {
  783.     if (BlockMarked(wnd))    {
  784.         ClearBlock(wnd);
  785.         SendMessage(wnd, PAINT, 0, 0);
  786.     }
  787.     dragcount = -1;
  788.     /* ------ set the anchor ------ */
  789.     wnd->BlkBegLine = wnd->BlkEndLine = my;
  790.     wnd->BlkBegCol = wnd->BlkEndCol = mx;
  791.     WriteTextLine(wnd, NULL, my, FALSE);
  792. }
  793.  
  794. static void Forward(WINDOW wnd)
  795. {
  796.     if (*(CurrChar+1) == '\0')
  797.         return;
  798.     if (*CurrChar == '\n')    {
  799.         Home(wnd);
  800.         Downward(wnd);
  801.     }
  802.     else    {
  803.         wnd->CurrCol++;
  804.         if (WndCol == ClientWidth(wnd))    {
  805.             wnd->wleft++;
  806.             SendMessage(wnd, PAINT, 0, 0);
  807.         }
  808.     }
  809. }
  810.  
  811. static void StickEnd(WINDOW wnd)
  812. {
  813.     int len = (int) (strchr(wnd->CurrLine, '\n') - wnd->CurrLine);
  814.  
  815.     wnd->CurrCol = min(len, wnd->CurrCol);
  816.     if (wnd->wleft > wnd->CurrCol)    {
  817.         wnd->wleft = max(0, wnd->CurrCol - 4);
  818.         SendMessage(wnd, PAINT, 0, 0);
  819.     }
  820.     else if (wnd->CurrCol-wnd->wleft >= ClientWidth(wnd))    {
  821.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  822.         SendMessage(wnd, PAINT, 0, 0);
  823.     }
  824. }
  825.  
  826. static void Downward(WINDOW wnd)
  827. {
  828.     if (isMultiLine(wnd) && wnd->WndRow+wnd->wtop+1 < wnd->wlines)    {
  829.         DownLine(wnd);
  830.         if (wnd->WndRow == ClientHeight(wnd)-1)    {
  831.             if (wnd->wtop+ClientHeight(wnd) <= wnd->wlines)    {
  832.                 wnd->wtop++;
  833.                 SendMessage(wnd, PAINT, 0, 0);
  834.             }
  835.         }
  836.         else
  837.             wnd->WndRow++;
  838.         StickEnd(wnd);
  839.     }
  840. }
  841.  
  842. static void DownLine(WINDOW wnd)
  843. {
  844.     wnd->CurrLine = strchr(wnd->CurrLine, '\n');
  845.     wnd->CurrLine++;
  846. }
  847.  
  848. static void UpLine(WINDOW wnd)
  849. {
  850.     --wnd->CurrLine;
  851.     if (wnd->CurrLine != wnd->text)    {
  852.         --wnd->CurrLine;
  853.         while (wnd->CurrLine != wnd->text && *wnd->CurrLine != '\n')
  854.             --wnd->CurrLine;
  855.         if (*wnd->CurrLine == '\n')
  856.             wnd->CurrLine++;
  857.     }
  858. }
  859.  
  860. static void Upward(WINDOW wnd)
  861. {
  862.     if (isMultiLine(wnd) && wnd->CurrLine != wnd->text)    {
  863.         UpLine(wnd);
  864.         if (wnd->WndRow == 0)    {
  865.             if (wnd->wtop)    {
  866.                 --wnd->wtop;
  867.                 SendMessage(wnd, PAINT, 0, 0);
  868.             }
  869.         }
  870.         else
  871.             --wnd->WndRow;
  872.         StickEnd(wnd);
  873.     }
  874. }
  875.  
  876. static void Backward(WINDOW wnd)
  877. {
  878.     if (wnd->CurrCol)    {
  879.         if (wnd->CurrCol-- <= wnd->wleft)    {
  880.             if (wnd->wleft != 0)    {
  881.                 --wnd->wleft;
  882.                 SendMessage(wnd, PAINT, 0, 0);
  883.                 return;
  884.             }
  885.         }
  886.         else
  887.             return ;
  888.     }
  889.     if (isMultiLine(wnd) && wnd->CurrLine != wnd->text)    {
  890.         Upward(wnd);
  891.         End(wnd);
  892.     }
  893. }
  894.  
  895. static void End(WINDOW wnd)
  896. {
  897.     while (*CurrChar != '\n')
  898.         ++wnd->CurrCol;
  899.     if (WndCol >= ClientWidth(wnd))    {
  900.         wnd->wleft = wnd->CurrCol - (ClientWidth(wnd)-1);
  901.         SendMessage(wnd, PAINT, 0, 0);
  902.     }
  903. }
  904.  
  905. static void Home(WINDOW wnd)
  906. {
  907.     wnd->CurrCol = 0;
  908.     if (wnd->wleft != 0)    {
  909.         wnd->wleft = 0;
  910.         SendMessage(wnd, PAINT, 0, 0);
  911.     }
  912. }
  913.  
  914. static char *FindLinePointer(WINDOW wnd, int ln)
  915. {
  916.     char *cp = wnd->text;
  917.     while (ln--)    {
  918.         cp = strchr(cp, '\n');
  919.         cp++;
  920.     }
  921.     return cp;
  922. }
  923.  
  924. #define isWhite(c)     ((c) == ' ' || (c) == '\n')
  925.  
  926. static void NextWord(WINDOW wnd)
  927. {
  928.     int savetop = wnd->wtop;
  929.     int saveleft = wnd->wleft;
  930.     ClearVisible(wnd);
  931.     while (!isWhite(*CurrChar))    {
  932.         if (*(CurrChar+1) == '\0')
  933.             break;
  934.         Forward(wnd);
  935.     }
  936.     while (isWhite(*CurrChar))    {
  937.         if (*(CurrChar+1) == '\0')
  938.             break;
  939.         Forward(wnd);
  940.     }
  941.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  942.     SetVisible(wnd);
  943.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  944.         SendMessage(wnd, PAINT, 0, 0);
  945. }
  946.  
  947. static void PrevWord(WINDOW wnd)
  948. {
  949.     int savetop = wnd->wtop;
  950.     int saveleft = wnd->wleft;
  951.     ClearVisible(wnd);
  952.     Backward(wnd);
  953.     while (isWhite(*CurrChar))    {
  954.         if (wnd->CurrLine == wnd->text && wnd->CurrCol == 0)
  955.             break;
  956.         Backward(wnd);
  957.     }
  958.     while (!isWhite(*CurrChar))    {
  959.         if (wnd->CurrLine == wnd->text && wnd->CurrCol == 0)
  960.             break;
  961.         Backward(wnd);
  962.     }
  963.     if (isWhite(*CurrChar))
  964.         Forward(wnd);
  965.     if (wnd->wleft != saveleft)
  966.         if (wnd->CurrCol >= saveleft)
  967.             if (wnd->CurrCol - saveleft < ClientWidth(wnd))
  968.                 wnd->wleft = saveleft;
  969.     SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  970.     SetVisible(wnd);
  971.     if (wnd->wtop != savetop || wnd->wleft != saveleft)
  972.         SendMessage(wnd, PAINT, 0, 0);
  973. }
  974.  
  975. static void ResetEditBox(WINDOW wnd)
  976. {
  977.     *wnd->text = '\0';
  978.     wnd->wlines = 0;
  979.     wnd->CurrLine = wnd->text;
  980.     wnd->CurrCol = 0;
  981.     wnd->WndRow = 0;
  982.     wnd->TextChanged = FALSE;
  983.     wnd->wleft = 0;
  984. }
  985.  
  986.